package com.qcxy.gzy.app;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import com.qcxy.gzy.activity.R;
import com.qxcy.gzy.util.PermissionUtils;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.Permission;

@SuppressLint("SdCardPath")
public class CrashExceptions implements Thread.UncaughtExceptionHandler {

	private static final String TAG = CrashExceptions.class.getSimpleName();
	private static CrashExceptions instance = null;
	private static Context mContext = null;
	private static ComApplication mApp;

	/** 系统默认的 UncaughtException 处理类 */
	private static Thread.UncaughtExceptionHandler mDefaultHandler;

	/** save device info and other exception info */
	private Map<String, String> infos = new HashMap<String, String>();

	/** date format: used for crash file name */
	private DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
	private String mCrashFilePath = "";

	private CrashExceptions() {
	}

	public static CrashExceptions getInstance(ComApplication a) {
		mContext = a;
		mApp = a;
		if (instance == null) {
			instance = new CrashExceptions();
		}

		mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();

		return instance;
	}

	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		if (handleException(ex) || mDefaultHandler == null) {
			sendCrashLogToServer(mCrashFilePath);
		} else {
			mDefaultHandler.uncaughtException(thread, ex);
		}
	}

	/**
	 * 自定义错误处理，收集错误信息，发送错误报告等操作均在此完成
	 * 
	 * @param ex
	 * @return true: 如果处理了该异常信息；否则返回 false
	 */
	private boolean handleException(final Throwable ex) {
		if (ex == null) {
			return false;
		}

		new Thread() {
			@Override
			public void run() {
				Looper.prepare();
				// 使用 Toast 来显示异常信息
				Toast.makeText(mContext, R.string.crash_toast,
						Toast.LENGTH_LONG).show();
				Looper.loop();
			}
		}.start();

		// collect device info
		//collectDeviceInfo(mContext);
		// save crash log to file
		mCrashFilePath = saveCrashInfo2File(ex);
//		PermissionUtils.createRequest(mContext, new Action<List<String>>() {
//
//			@Override
//			public void onAction(List<String> data) {
//				mCrashFilePath = saveCrashInfo2File(ex);
//			}
//		}, Permission.Group.STORAGE).start();
		return true;
	}

	private void sendCrashLogToServer(final String path) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				if (path != null && !"".equals(path)) {
					// FileUtil.sendCrashInfo2Server(path);
				}
				// 退出程序,注释下面的重启启动程序代码
				// restart this application
				// android.os.Process.killProcess(android.os.Process.myPid());
				System.exit(1);
			}
		}).start();
	}

	/**
	 * 收集设备参数信息
	 * 
	 * @param ctx
	 */
	private void collectDeviceInfo(Context ctx) {
		try {
			PackageManager pm = ctx.getPackageManager();
			PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
					PackageManager.GET_ACTIVITIES);

			if (pi != null) {
				String versionName = pi.versionName == null ? "null"
						: pi.versionName;
				String versionCode = pi.versionCode + "";
				infos.put("versionName", versionName);
				infos.put("versionCode", versionCode);
			}
		} catch (NameNotFoundException e) {
			Log.e(TAG, "an error occured when collect package info", e);
		}

		Field[] fields = Build.class.getDeclaredFields();
		for (Field field : fields) {
			try {
				field.setAccessible(true);
				infos.put(field.getName(), field.get(null).toString());
			} catch (Exception e) {
				Log.e(TAG, "an error occured when collect crash info", e);
			}
		}
	}

	/**
	 * 保存错误信息到文件中
	 * 
	 * @param ex
	 * @return 返回文件名称,便于将文件传送到服务器
	 */
	private String saveCrashInfo2File(Throwable ex) {
		String logFullPath = null;
		StringBuffer sb = new StringBuffer();
		sb.append("CurrentActivity: " + mApp.getCurrentActivityName() + "\n");
		sb.append("---------------------------------------------------\n");
		for (Map.Entry<String, String> entry : infos.entrySet()) {
			String key = entry.getKey();
			String value = entry.getValue();
			sb.append(key + "=" + value + "\n");
		}

		Writer writer = new StringWriter();
		PrintWriter printWriter = new PrintWriter(writer);
		ex.printStackTrace(printWriter);
		Throwable cause = ex.getCause();
		while (cause != null) {
			cause.printStackTrace(printWriter);
			cause = cause.getCause();
		}
		if (printWriter != null) {
			printWriter.close();
		}

		String result = writer.toString();
		sb.append(result);
		try {
			long timestamp = System.currentTimeMillis();
			String time = formatter.format(new Date());
			String fileName = "crash-" + time + "-" + timestamp + ".log";
			if (Environment.getExternalStorageState().equals(
					Environment.MEDIA_MOUNTED)) {
				String folder = "/sdcard/crash/";
				File dir = new File(folder);
				if (!dir.exists()) {
					dir.mkdirs();
				}
				logFullPath = folder + File.separator + fileName;
				FileOutputStream fos = new FileOutputStream(logFullPath);
				fos.write(sb.toString().getBytes());
				if (fos != null) {
					fos.close();
				}

				return logFullPath;
			}
		} catch (Exception e) {
			Log.e(TAG, "an error occured while writing file...", e);
		}

		return logFullPath;
	}
}